﻿using System;
using System.Windows;

namespace Black.SurfaceToolkit.Tools
{
    /// <summary>
    /// Représente un cercle.
    /// </summary>
    public class Circle
    {
        #region Accesseurs

        /// <summary>
        /// Obtient ou définit le centre du cercle.
        /// </summary>
        public Point Center
        {
            get;
            set;
        }

        /// <summary>
        /// Obtient ou définit le rayon du cercle.
        /// </summary>
        public double Rayon
        {
            get;
            set;
        }

        #endregion

        #region Variables statiques

        /// <summary>
        /// Représente le cercle de rayon 0.
        /// </summary>
        public static readonly Circle Empty = new Circle(new Point(0, 0), 0);

        #endregion

        #region Constructeurs

        /// <summary>
        /// Initialise une nouvelle instance de <see cref="T:Black.SurfaceToolkit.Tools.Circle" />.
        /// </summary>
        /// <param name="p_oCenter">Centre du cercle.</param>
        /// <param name="p_dRayon">Rayon du cercle.</param>
        public Circle(Point p_oCenter, double p_dRayon)
            : base()
        {
            this.Center = p_oCenter;
            this.Rayon = p_dRayon;
        }

        #endregion

        #region Fonctions publiques

        /// <summary>
        /// Obtient une valeur indiquant si le cercle spécifié et ce cercle ont une intersection non vide.
        /// </summary>
        /// <param name="p_oCercle">Second cercle.</param>
        /// <returns><see langword="true" /> si <paramref name="p_oCercle" /> et ce cercle ont une intersection non vide, <see langword="false" /> sinon.</returns>
        public bool Intersect(Circle p_oCercle)
        {
            return (Circle.Intersect(this, p_oCercle));
        }

        /// <summary>
        /// Obtient une valeur indiquant si le point spécifié est dans le cercle.
        /// </summary>
        /// <param name="p_oPoint">Point dont on veut savoir s'il est dans le cercle.</param>
        /// <returns><see langword="true" /> si <paramref name="p_oPoint" /> est dans le cercle, <see langword="false" /> sinon.</returns>
        public bool PointInCircle(Point p_oPoint)
        {
            return (Circle.PointInCircle(this, p_oPoint));
        }

        /// <summary>
        /// Obtient la représentation de l'objet sous forme de chaîne de caractères.
        /// </summary>
        /// <returns>Représentation de l'objet sous forme de chaîne de caractères.</returns>
        public override string ToString()
        {
            return (string.Format("Center: {0}p_dX{1} - Rayon: {2}", this.Center.X, this.Center.Y, this.Rayon));
        }

        #endregion

        #region Fonctions statiques

        /// <summary>
        /// Obtient une valeur indiquant si deux cercles ont une intersection non vide.
        /// </summary>
        /// <param name="p_oCercle1">Premier cercle.</param>
        /// <param name="p_oCercle2">Second cercle.</param>
        /// <returns><see langword="true" /> si <paramref name="p_oCercle1" /> et <paramref name="p_oCercle2" /> ont une intersection non vide, <see langword="false" /> sinon.</returns>
        public static bool Intersect(Circle p_oCercle1, Circle p_oCercle2)
        {
            double dDistance;

            // On calcul la dDistance entre les deux centres

            dDistance = Math.Sqrt(Math.Pow(p_oCercle1.Center.X - p_oCercle2.Center.X, 2) + Math.Pow(p_oCercle1.Center.Y - p_oCercle2.Center.Y, 2));

            // Test intersection

            if (dDistance > (p_oCercle1.Rayon + p_oCercle2.Rayon))
                return (false);

            // Pas d'intersection

            return (true);
        }

        /// <summary>
        /// Obtient une valeur indiquant si le point spécifié est dans le cercle spécifié.
        /// </summary>
        /// <param name="p_oCercle">Cercle dont on veut savoir s'il contient le point.</param>
        /// <param name="p_oPoint">Point dont on veut savoir s'il est dans le cercle.</param>
        /// <returns><see langword="true" /> si <paramref name="p_oPoint" /> est dans <paramref name="p_oCercle"/>, <see langword="false" /> sinon.</returns>
        public static bool PointInCircle(Circle p_oCercle, Point p_oPoint)
        {
            double dX = Math.Pow(p_oPoint.X - p_oCercle.Center.X, 2);
            double dY = Math.Pow(p_oPoint.Y - p_oCercle.Center.Y, 2);

            return (Math.Sqrt(dX + dY) <= p_oCercle.Rayon);
        }

        #endregion
    }
}
